import React, { Component, Fragment, useState, useEffect,useContext  } from 'react';
import ReactDOM from 'react-dom';
import AppRouter from './AppRouter'
import './index.css';
import './css/index.css'

import axios from 'axios'
import TodoList from './todo'
import Example4 from './pages/Example4'

// 为了使用react-redux的代码
import { Provider } from 'react-redux'
import store from './store'

// 路由哦
import Getup from './pages/workplace/Getup'
import Money from './pages/workplace/Money'
import home from './pages/home'
import Nav from './nav';
import Error from './error'
import { BrowserRouter as Router, Link, HashRouter, MemoryRouter, Route, Switch, Redirect } from 'react-router-dom';
import Example7 from './pages/useRef/example'
// import TodoList from './TodoList'
// import App from './App';
// import * as serviceWorker from './serviceWorker';
// ReactDOM.render(<App />, document.getElementById('root'));

// // If you want your app to work offline and load faster, you can change
// // unregister() to register() below. Note this comes with some pitfalls.
// // Learn more about service workers: https://bit.ly/CRA-PWA
// serviceWorker.unregister();
// jsx注释问题 用{}包裹起来，遇到{}当js处理，遇到《》当html处理
// 因为 JSX 语法上更接近 JavaScript 而不是 HTML，所以 React DOM 使用 camelCase（小驼峰命名）来定义属性的名称，而不使用 HTML 属性名称的命名约定
// JSX中的class陷阱 class="input"错误，而是className="input" css一样
// JSX中的html解析问题，使用dangerouslySetInnerHTML属性解决
// jsx的label标签for的属性=》htmlFor属性

//搭配react-thunk的原因所以第一种变量写法会报错
// const Appp = (
//   <Provider store={store}>
//     {/* 这里面的所有组件都可以应用 */}
//       <TodoList></TodoList>
//   </Provider>
// )
//React Hooks 写法：都可以用函数来声明

// class Example extends React.Component {
//     constructor(props) {
//         super(props);
//         this.state = { count:0 }
//     }
//     // 初始渲染执行
//     componentDidMount(){
//       console.log(`ComponentDidMount=>You clicked ${this.state.count} times`)
//   }
//   // 组件更新执行
//   componentDidUpdate(){
//       console.log(`componentDidUpdate=>You clicked ${this.state.count} times`)
//   }
//     render() { 
//         return (
//             <div>
//                 <p>You clicked {this.state.count} times</p>
//                 <button onClick={this.addCount.bind(this)}>Chlick me</button>
//             </div>
//         );
//     }
//     addCount(){
//         this.setState({count:this.state.count+1})
//     }
// }
function Index() {
  useEffect(() => {
    console.log('useEffect=>老弟，你来了！Index页面')
    return () => {
      // 第二个参数的作用解绑，切换别的组件就会执行这个打印代替componentWillUnmount
      // 当状态值发生变化时，我们才进行解绑。但是当传空数组[]时，就是当组件将被销毁时才进行解绑，这也就实现了componentWillUnmount的生命周期函数。
      console.log('老弟，你走了!Index页面')
    }
  },[])
  return <h2>JSPang.com</h2>;
}

function List() {
  useEffect(() => {
    console.log('useEffect=>老弟，你来了！List页面')
  })
  return <h2>List-Page</h2>;
}

//  改进react hook写法,简单化周期，数据存储，父子组件传值
function Example() {
  const [count, setCount] = useState(0)
  //   let _useState = userState(0)
  // let count = _useState[0]
  // let setCount = _useState[1]

  const [age, setAge] = useState(18)
  const [sex, setSex] = useState('男')
  const [work, setWork] = useState('前端程序员')
  // useState的用法，分别是声明、读取、使用（修改）代表原生类组件的第一个函数参数首次渲染(componentDidMonut)和更新导致的重新渲染(componentDidUpdate)
  // useState这个函数接收的参数0是状态的初始值(Initial state)，它返回一个数组，这个数组的第0位count是当前的状态值，第1位setCount是可以改变状态值的方法函数。 
  console.log(count, setCount, useState(0))
  // 第一次组件渲染和每次组件更新都会执行这个函数,不同原版。
  //他是异步执行，当传空数组[]时，就是当组件将被销毁时才进行解绑,同时每次状态发生变化，useEffect都进行了解解绑流程
  useEffect(() => {
  // 只有组件渲染和更新都会调动这个函数
    console.log(`useEffect=>You clicked ${count} times`)
  // 返回一个函数可以解绑
    return ()=>{
      console.log('====================')
    }
    // useEffect在组件mount时执行，但也会在组件更新时执行。因为我们在每次请求数据之后都会设置本地的状态数据变化就重新渲染组件，所以组件会更新，因此useEffect会再次执行，因此出现了无限循环的情况，我们只想在组件mount时请求数据。我们可以传递一个空数组作为useEffect的第二个参数，这样就能避免在组件更新执行useEffect，只会在组件mount时执行
  // 每次count发生变化会重新更新这个组件，我们都进行解绑
  },[count])
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => { setCount(count + 1) }}>click me</button>
      <p>JSPang 今年:{age}岁</p>
      <p>性别:{sex}</p>
      <p>工作是:{work}</p>
      <Router>
        <ul>
          <li> <Link to="/">首页</Link> </li>
          <li><Link to="/list/">列表</Link> </li>
        </ul>
        <Route path="/" exact component={Index} />
        <Route path="/list/" component={List} />
      </Router>
    </div>
  )
}

function Appp() {
  return (
    <Provider store={store}>
      {/* 这里面的所有组件都可以应用 */}
      <TodoList></TodoList>
    </Provider>
  )
}


function formatName(user) {
  if (user) {
    return user.firstName + ' ' + user.lastName;
  } else {
    return <h1>hello.stranger</h1>
  }
}
function name(a) {
  if (a) {
    return a
  }
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};
const element = (
  <div>
    <h1> hello!</h1>
    <h2>good to see you here.</h2>
  </div>
);

// element1 与 element2等价。element为一个函数调用预先检查
const element1 = (
  <h1>
    Hello, {formatName(user)}!
    </h1>
);

const element2 = React.createElement(
  'h1',
  { className: "greeting" },
  'hello,world！'
)
// 简化
const element3 = (
  <p>
    <span>hello<i>user.name</i></span>
    <div><h2>hh</h2></div>
  </p>
)

// 根节点root里面为react管理
// ReactDOM.render(
//   element3,
//   document.getElementById('root')
// );
//  一般来说一个元素只会创建一次 ReactDOM.render()。同一个元素用两次reactdom.render,会报错。
function tick1() {
  const element = (
    <div>
      <h1>hello,world!</h1>
      <h2>
        it is {new Date().toLocaleTimeString()}
      </h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'))
}
// 第一种 函数组件
// setInterval(tick1,1000)

//  组件开始 props是一个对象，他可以接受传过来的属性
function Welcome(props) {
  return <h1>hello,{props.name}</h1>
}
// 或者
class Welcome1 extends React.Component {
  render() {
    return <h1>hello,{this.props.name}</h1>
  }
}

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <span>nihap</span>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    // props接收传数据到组件内部
    <Clock date={new Date()}></Clock>,
    document.getElementById('root')

  )
}
// 第二种通过props传值实现视图更新，组装组件，不断时间长短是间隔一秒更新调用函数传时间到组件进行更新界面时间
// setInterval(tick,1000)
// 用另一种方式state[私有的]代替props，构造函数是唯一可以给 this.state 赋值的地方：

// class组件
class Clock1 extends React.Component {
  // 构造函数
  constructor(props) {
    super(props);
    this.state = { date: new Date() }
  }
  // 自定义方法//this.setState() 来时刻更新组件 
  //state不要直接修改 State,this.state.date = 'Hello'构造函数是唯一可以给 this.state 赋值的地方：


  tick() {
    // 视图问题根本不会更新，还是最初的样子,1箭头函数内容如果只有一条语句，可以将{}和return省略掉，2如果返回的内容是一个对象{a:1,b:2}，对象需要用括号（）括起来，3当没有参数或有多个参数时，需要用括号（）括起来:
    //当你调用 setState() 的时候，React 会把你提供的对象合并到当前的 state,但是分别调用更新自己只对自己有影响不影响别的变量
    // 直接给state赋值无作用，this.state.date = new Date()
    this.setState({
      date: new Date()
    });
  }
  // 生命周期 每秒调用tick方法 周期结束时清楚这个方法 计时器用变量接收
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  //渲染
  render() {
    return (
      <div>
        <h1> 111111111111</h1>
        {/* 更新私有时间state.date时间通过调用方法实现*/}
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    )
  };
}
// 第三种就是通过state私有变量传值，class定义一个组件为类。
// ReactDOM.render(
//   <Clock1></Clock1>,
//   document.getElementById('root')
// )
// 组合组件
function Welcome3(props) {
  return <h1>hello,{props.name}</h1>
}
function App() {
  return (
    <div>
      <Welcome3 name='sara'></Welcome3>
      <Welcome3 name='chra'></Welcome3>
      <Welcome3 name='lan'></Welcome3>
    </div>
  )
}

// ReactDOM.render(
//   <App />,
//   document.getElementById('root')
// )
// 评论功能,解决组件不能复用问题
function Avatar(props) {
  return (
    <img className='Avatar'
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  )
}
function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}
function Comment(props) {
  return (
    <div className='Comment'>
      <UserInfo user={props.author} />
      <div className='Comment-text'>
        {props.text}
      </div>
      <div className='Comment-date'>
        {/* {formatDate(props.date)} */}
      </div>
    </div>
  )
}
const userinfo = {
  author: { user: { name: 'lanhua', avatarUrl: 'ssss' } },
  text: 'Perez'
};


// ReactDOM.render(
//   <Comment userinfo={userinfo}/>,
//   document.getElementById('root')
// )

// 事件处理 
// React 事件的命名采用小驼峰式（camelCase），而不是纯小写。
// 使用 JSX 语法时你需要传入一个函数作为事件处理函数，而不是一个字符串。

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked')
  }
  return (
    <a href='#' onClick={handleClick}> click me</a>
  )
}
// ReactDOM.render(
//  <ActionLink></ActionLink>,
//  document.getElementById('root')
// )

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isToggleOn: true }
    // 把函数内部指向的this指向组件的this
    this.handleClick = this.handleClick.bind(this)
  }
  // f.bind(a),把f的this指向bind的第一个参数a,this.setstate可以接受对象/函数
  handleClick() {
    // 本身这个函数里面的this只是指向这个click函数，如果是箭头函数指向上一级，也就是组件的this
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }))
  }

  render() {
    return (
      <button onClick={this.handleClick}>{this.state.isToggleOn ? 'on' : 'off'}</button>
      // 再循环传递参数
      // <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
    )
  }
}
// 条件渲染
function UserGreeting(props) {
  return <h1>Welcome back!</h1>
}
function GuestGreeting(props) {
  return <h1>please sign up.</h1>
}
// 自定义组件名使用函数一定要首字母大写 识别组件标签，不然认为是会将以小写字母开头的组件视为原生 DOM 标签
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />
  }
  return <GuestGreeting />
}
// ReactDOM.render(
//   <Greeting isLoggedIn={true} />,
//   document.getElementById('root')
// )
function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  )
}
function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  )
}

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    // 首先定义一个初始化的值
    this.state = { isLoggedIn: false }
  }
  handleLoginClick() {
    this.setState({ isLoggedIn: true });
  }
  handleLogoutClick() {
    this.setState({ isLoggedIn: false })
  }
  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    // 如果是登录状态给出退出按钮组件 点击退出。如果是未登陆给出登录按钮组件 点击登录成功【在组件上注册事件 把一个方法对象传给组件内部 可】
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />
    }
    return (
      <div>
        {/* 现在可以炒作按钮随意改变isLoggedIn的状态 */}
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    )
  }
}
// ReactDOM.render(
//   <LoginControl />,
//   document.getElementById('root')
// )

//通过花括号{}包裹代码，你可以在 JSX 中嵌入任何表达式。这也包括 JavaScript 中的逻辑与 (&&) 运算符

// 运算符 &&
function Mailbox(props) {
  const unreadMessage = props.unreadMessage;
  return (
    <div>
      <h1>hello！</h1>
      {unreadMessage.length < 0 &&
        <h2>
          You have {unreadMessage.length} unread message.
      </h2>
      }
    </div>
  )
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
// ReactDOM.render(
//   // 函数组件传值，props把message传进去
//   // 在 JavaScript 中，true && expression 总是会返回 expression, 而 false && expression 总是会返回 false
//   <Mailbox unreadMessage={messages}></Mailbox>,
//   document.getElementById('root')
// );

// 三元表达式  condition ? true : false。LoginControl类组件的render·函数
// render() {
//   const isLoggedIn = this.state.isLoggedIn;
//   return (
//      <div>
//       The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in
//     </div>
//   );
// }
// render(){
//   const isLoggedIn = this.state.isLoggedIn;
//   return(
//     <div>
//       {
//       isToggleIn ? (<LogoutButton onClick={this.handleLogoutClick}></LogoutButton>) : (<LoginButton onClick={this.handleLoginClick}></LoginButton>)
//       }
//     </div>
//   )
// }

// 阻止组件渲染//一定要注意组件名首字符大写。./极少数情况下，你可能希望能隐藏组件，以让 render 方法直接返回 null，而不进行任何渲染，render 方法中返回 null 并不会影响组件的生命周期
function WarningBanner(props) {

  if (!props.warn) {
    return null;
  }
  return (
    <div className='warning'> Warning !</div>
  )
}
// 注意：React
class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = { showWarning: true };
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      // 组件、jsx用()包起来
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}> {this.state.showWarning ? 'Hide' : 'Show'}</button>
      </div>
    )
  };
}

// ReactDOM.render(
//   <Page></Page>,
//   document.getElementById('root')
// )

// 列表 & key
const numbers = [1, 2, 3, 4, 5]
const listItems = numbers.map((number) => <li>{number}</li>);
// console.log(doubled,numbers)

// ReactDOM.render(
//   <ul>{listItems}</ul>,
//   document.getElementById('root')
// )

// 基础列表组件
// 一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常，我们使用来自数据 id 来作为元素的 key：key 只有放在就近的数组上下文中才有意义,如果你提取 出一个 ListItem 组件，你应该把 key 保留在数组中的这个 <ListItem /> 元素上，而不是放在 ListItem 组件中的 <li> 元素上
// key 只是在兄弟节点之间必须唯一,生成两个不同的数组时，我们可以使用相同的 key 值：
function NumberList(props) {
  const numbers = props.number;
  const listItems = numbers.map((number) => <li key={number.toString()}>{number}</li>);
  return (<ul>{listItems}</ul>)
};
// ReactDOM.render(
//   <NumberList number={numbers}></NumberList>,
//   document.getElementById('root')
// )

// 表单
class EssaForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: "请撰写一篇关于你喜欢的 DOM 元素的文章" };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  };
  handleChange(event) {
    // 主要有值变化就会触发这个事件更改state的value值
    console.log(event.target.value)
    this.setState({ value: event.target.value });
  };
  handleSubmit(event) {
    alert('提交的名字：' + this.state.value);
    event.preventDefault();
  }
  render() {
    return (
      //  onsubmit只能表单上使用,提交表单前会触发
      <form onSubmit={this.handleSubmit}>
        <label>
          名字：
           <input type='text' value={this.state.value} onChange={this.handleChange}></input>
        </label>
        <input type='submit' value='提交'></input>
      </form>
    )
  }
}
// ReactDOM.render(
//   <EssaForm></EssaForm>,
//   document.getElementById('root')
// )
class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: 'coconut' };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleChange(event) {
    this.setState({ value: event.target.value });
  }
  handleSubmit(event) {
    alert('你喜欢的风味是：' + this.state.value);
    event.preventDefault()
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          选择你喜欢的风格：
        <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">葡萄柚</option>
            <option value="lime">酸橙</option>
            <option value="coconut">椰子</option>
            <option value="mango">芒果</option>
          </select>
        </label>
        <input type="submit" value="提交" />
      </form>
    )
  }
}
// ReactDOM.render(
//   <FlavorForm></FlavorForm>,
//   document.getElementById('root')
// )


class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // 默认表单被选择和默认来兵人数
      isGoing: true,
      numberOfGuests: 2
    };
    this.handleInputChange = this.handleInputChange.bind(this);
  }
  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    //  es6计算属性名称的语法更新给定输入名称对应的 state 值
    this.setState({
      [name]: value
    });
    // console.log(this.state)
  }

  render(h) {
    return (
      <form>
        <lable>
          参与：
          <input name='isGoing' type='checkbox' checked={this.state.isGoing} onChange={this.handleInputChange}></input>
        </lable>
        <br />
        <label>
          来宾人数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    )
  }
}
// ReactDOM.render(
//   <Reservation></Reservation>,
//   document.getElementById('root')
// )

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>the.water would boil</p>
  }
  return <p>the water would not boil</p>
}

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = { temperature: "" }
  }

  handleChange(e) {
    this.setState({ temperature: e.target.value })
  }

  render() {
    const temperature = this.state.temperature;
    return (
      <fieldset>
        {/* 一定要用个根元素元素包裹 */}
        <legend>enter temperature in celsius</legend>
        <input value={temperature} onChange={this.handleChange}></input>
        {/* 注册了一个属性传给组件 */}
        <BoilingVerdict celsius={parseFloat(temperature)}></BoilingVerdict>
      </fieldset>

    )
  }
}
// ReactDOM.render(
//   <Calculator></Calculator>,
//   document.getElementById('root')
// )
// 如果其他组件也需要这个 state，那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流
const scaleNames = {
  c: 'Celsius',
  f: "Fahrenheit"
};

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    // this.state = {temperature:""}
  }

  handleChange(e) {
    // 数据来源是props，setstate失去控制权
    // this.setState({temperature:e.target.value})
    this.props.onTemperatureChange(e.target.value);
    console.log(this.props)
  }

  render() {
    // 这个是本地数据源。我们需要组件外继承的temperature
    // const temperature = this.state.temperature;
    const temperature = this.props.temperature;
    // 继承组件传过来的属性
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature} onChange={this.handleChange} />
      </fieldset>
    )
  }
}
// 摄氏度和华氏度换算
function toCelsius(fahrenheit) {
  return (fahrenheit - 32) * 5 / 9;
}

function toFahrenheit(celsius) {
  return (celsius * 9 / 5) + 32;
}

function tryConvert(temperature, convert) {
  // convert传的一个温度值和一个计算方法
  const input = parseFloat(temperature);
  //判断是不是数字类型，不是返回空字符串
  if (Number.isNaN(input)) {
    return '';
  }
  const output = convert(input);
  //本身是round是取整，如果保留三位小数的话就*1000再除1000，返回一个字符串
  const rounded = Math.round(output * 1000) / 1000;
  return rounded.toString()
}

class Calculators extends React.Component {
  //现在统一控制temperature
  constructor(props) {
    super(props);
    this.handCelsiusChange = this.handCelsiusChange.bind(this);
    this.handleFahrenheiChange = this.handleFahrenheiChange.bind(this);
    this.state = { temperature: '', scale: "c" }
  }
  // 把方法传到
  handCelsiusChange(temperature) {
    // setState只要变化就更新组件
    this.setState({ scale: 'c', temperature })
  }
  handleFahrenheiChange(temperature) {
    this.setState({ scale: "f", temperature })
  }
  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    // 判断输入的是摄氏还是华摄氏.如果输入华摄氏转换摄氏
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    // 如果输入摄氏。要用toFahrenheit转化为华摄氏的值传给另一个组件。他接受的是华摄氏值
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
    return (
      <div>
        <TemperatureInput scale='c' temperature={celsius}
          onTemperatureChange={this.handCelsiusChange} ></TemperatureInput>
        <TemperatureInput scale='f' temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheiChange}></TemperatureInput>
        <BoilingVerdict
          celsius={parseFloat(celsius)} />
      </div>
    )
  }
}
// ReactDOM.render(
//   <Calculators></Calculators>,
//   document.getElementById('root')
// )

// 组合vs继承
function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  )
}

function WelcomeDialog() {
  return (
    <FancyBorder color='blue' >
      <h1 className='Dialog-title'>
        Welcome
      </h1>
      <p className='Dialog-message'>
        Thank you visiting our spacecraft ！
      </p>
    </FancyBorder>

  )
}
// 传值组件作为props传过去
function SplitPane(props) {
  return (
    <div className='SplitPane'>
      <div className='SplitPane-left'>
        {props.left}
      </div>
      <div className='SplitPane-right'>
        {props.right}
      </div>
    </div>
  )
}

function Contacts(props) {
  return <div>左边</div>
}
function Chat() {
  return <div>右边</div>
}
function Apps() {
  return (
    <SplitPane left={<Contacts />} right={<Chat />} />
  )
}
// ReactDOM.render(
//   <WelcomeDialog />,
//   document.getElementById('root')
// )

function Dialog(props) {
  return (
    <FancyBorder color='blue'>
      <h1 className='Dialog-title'>{props.title}</h1>
      <p className='Dialog-message'>{props.message}</p>
      {/*  需要什么子组件传什么过来，这边找childern占位置，使用一个特殊的 children prop 来将他们的子组件 input/button传递到渲染结果位置中： */}
      {props.children}
    </FancyBorder>
  )
}

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handSignUp = this.handSignUp.bind(this);
    this.state = { login: "" };
  }

  handleChange(e) {
    this.setState({ login: e.target.value })
  }
  handSignUp() {
    alert('welcome aboard' + this.state.login)
  }
  render() {
    return (
      <Dialog title="Mars Exploration Program" message="How should we refer to you?">
        <input value={this.state.login} onChange={this.handleChange}></input>
        <button onClick={this.handleSignUp}> Sign up</button>
      </Dialog>
    )
  }
}
function WelcomeDialog1() {
  return (
    <Dialog title='welcome' message='Thank you for visiting our spacecraft'>

    </Dialog>
  )
}

// ReactDOM.render(
//   <SignUpDialog></SignUpDialog>,
//   document.getElementById('root')
// )
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.inputElement = React.createRef();
  }
  render() {
    return (

      <CustomTextInput inputRef={this.inputElement} />
    );
  }

  focus() {
    // 使用原始的 DOM API 显式地聚焦在 text input 上
    // 注意：我们通过访问 “current” 来获得 DOM 节点
    this.inputElement.current.focus();
  }
}

// ReactDOM.render(
//   <Parent></Parent>,
//   document.getElementById('root')
// )
var a = 100 / 3
class OuterClickExample extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOpen: false };
    this.toggleContainer = React.createRef()
    this.onClickHandler = this.onClickHandler.bind(this)
    this.onClickOutsideHander = this.onClickOutsideHander.bind(this)
  }
  componentDidMount() {
    // 组件渲染初期就开始监听今天window的所有点击事件，都会触发那个onClickOutsideHander函数。而这个函数是判断有么有点击在一个元素上，
    window.addEventListener('click', this.onClickOutsideHander)
  }
  componentWillUnmount() {
    window.removeEventListener('click', this.onClickOutsideHander)
  }
  onClickHandler() {
    this.setState(currentState => ({ isOpen: !currentState.isOpen }))
  }
  onClickOutsideHander(event) {
    // 只有当列表显示同时获取ref为toggleContainer的dom元素判断有没有这个对象，没点击在这个对象范围内
    if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) {
      // 把开关关闭。变成false
      this.setState({ isOpen: false })
    }
  }
  render() {
    return (
      // 不需要这个最外层的标签用Fragment 包裹
      <div ref={this.toggleContainer}>
        <span>{a}</span>
        <button onClick={this.onClickHandler}> select an option</button>
        {this.state.isOpen && (
          <ul>
            <li>option1</li>
            <li>option2</li>
            <li>option3</li>
          </ul>
        )}
      </div>
    )
  }
}
// ReactDOM.render(
//   <OuterClickExample></OuterClickExample>,
//   document.getElementById('root')
// )

class Xiaojiejie extends React.Component {
  // React的Initialization阶段
  constructor(props) {
    super(props) //调用父类的构造函数，固定写法
    this.state = {
      inputValue: 'jspang', // input中的值
      list: ['基础按摩', '精油推背']    //服务列表
    }
  }
  // 增加服务
  addList() {
    // ...这个是ES6的新语法，叫做扩展运算符。意思就是把list数组进行了分解，形成了新的数组，然后再进行组合
    this.setState({
      list: [...this.state.list, this.state.inputValue]
    })
  }
  // 删除服务
  deleteItem(index) {
    // 删除数据重新排列索引顺序会变化
    console.log(index)
    this.state.list.splice(index, 1)
    this.setState({
      list: this.state.list
    })
  }
  inputChange(e) {
    this.setState({
      inputValue: e.target.value
    })
  }
  // render()函数，就是一个生命周期函数，它在state发生改变时自动执行
  componentWillMount() {
    console.log('componentWillMount----组件将要挂载到页面的时刻')
  }
  componentDidMount() {
    axios.post('https://web-api.juejin.im/v3/web/wbbr/bgeda').then((res) => {
      console.log('获取数据成功：' + JSON.stringify(res))
    }).catch((err) => {
      console.log('获取数据失败·', err)
    })
  }
  // componentWillMount和componentDidMount这两个生命周期函数，只在页面刷新时执行一次render函数是只要有state和props变化就会执行
  // 0- componentWillReceiveProps(){---如果本组件是一个底层子组件接受props 第一次存在他不会执行，但是当他的dom更新才会执行这个函数
  // 1-shouldComponentUpdate---组件发生改变前执行，可以优化组件性能 利用参数：nextProps:变化后的属性;nextState:变化后的状态;
  // 2-componentWillUpdate---组件更新前，shouldComponentUpdate函数之后执行
  // 3-render----开始挂载渲染
  // 4-componentDidUpdate----组件更新之后执行
  shouldComponentUpdate() {
    console.log('shouldComponentUpdate 返回false后面周期不执行')

    return true
    console.log()
  }
  //当dom从页面中删除的时候执行
  componentWillUnmount() {
    console.log('child - componentWillUnmount')

  }

  render() {
    console.log('render---组件挂载中.......')
    return (
      <Fragment>
        <div>
          {/* jsx的for和js的for混淆，react改用了htmlFor */}
          {/* <label for='jspang'>加入服务可以激活id=jspang的input：</label> */}
          <label htmlFor='jspang'>加入服务可以激活id=jspang的input：</label>
          <input id='jspang' className='input' value={this.state.inputValue} onChange={this.inputChange.bind(this)}></input>
          <button onClick={this.addList.bind(this)}>增加服务</button>
        </div>
        <ul>
          {/*react的正确注释 开始解析jsx代码 ，注意用了dangerouslySetInnerHTML标签里面应该没有·内容，否则会报错如果·item输入标签<div>123</div>会被解析成标签*/}
          {
            this.state.list.map((item, index) => {
              return <li onClick={this.deleteItem.bind(this, index)} key={index + item} dangerouslySetInnerHTML={{ __html: item }}></li>
            })
          }
        </ul>
      </Fragment>
    )
  }
}

class Boss extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isShow: true
    }
    this.toToggole = this.toToggole.bind(this);
  }
  render() {
    return (
      <div className={this.state.isShow ? 'show' : 'hide'}>
        <div>boss级人物-孙悟空</div>
        <div>
          <button onClick={this.toToggole}>召唤Boss</button>
        </div>
      </div>
    );
  }
  toToggole() {
    this.setState({
      isShow: this.state.isShow ? false : true
    })
  }
}
// ReactDOM.render(
//   // 引入的TODOlist的外部组件
//   <AppRouter />,
//   document.getElementById('root')
// )
ReactDOM.render(
  // basename的作用是个我们增加一级导航目录/demo/jspang/
  // forceRefresh属性,开启或者关闭React Router,设置成真，它将关闭React路由系统，而真实的去服务器端请求信息。
  // <Router basename='demo' forceRefresh={true}>
  //     <div>
  //     <Nav/>
  //     <Switch>
  //       {/* **总结:**设置404和跳转都要先加入Switch的支持，在制作404时一定记得要把404的Route设置到所有路由的后边。跳转时使用Redirect标签，这个很容易实现。*/}
  //     <Redirect from="/react" to="/Jspangb" />

  //         <Route exact path="/" component={home} />
  //         <Route  path="/Jspangb" component={Money} />
  //         <Route   path="/Jspangc/:param"  component={Getup} />
  //         {/* 如果没有路由地址在路由器，就给给error */}
  //         <Route  component={Error} />
  //     </Switch>

  //     </div>
  // </Router>,
  // MemoryRouter,HashRouter
  //   <MemoryRouter basename="demo" >
  //     <div>
  //         <Nav/>
  //         <Switch>
  //         <Route exact path="/" component={home} />
  //           <Route  path="/Jspangb" component={Money} />
  //           <Route   path="/Jspangc/:param"  component={Getup} />
  //           {/* 如果没有路由地址在路由器，就给给error */}
  //            <Route  component={Error} />
  //         </Switch>

  //     </div>
  // </MemoryRouter>,
  <Example> </ Example>,
  document.getElementById("root")
);